package cn.edu.nju.ws.sview.views.data;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map.Entry;


import cn.edu.nju.ws.sview.cache.FalconURIIDCache;
import cn.edu.nju.ws.sview.cache.SameAsCache;
import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.cache.URILabelCache;
import cn.edu.nju.ws.sview.crawler.Crawler;
import cn.edu.nju.ws.sview.crawler.Element;
import cn.edu.nju.ws.sview.crawler.Fetch;
import cn.edu.nju.ws.sview.database.DBConnectionFactory;
import cn.edu.nju.ws.sview.database.DBOperations;
import cn.edu.nju.ws.sview.rdf.ResourceFactory;
import cn.edu.nju.ws.sview.rdf.URIResource;
import cn.edu.nju.ws.sview.views.Entity;
import cn.edu.nju.ws.sview.views.User;


/**
 * input hints
 * fetch the popular entities my entities
 * @author ssgong
 *
 */
class Log{
	int item_type;
	int item_id;
	String lang;
	Log(int id, int type, String lan){
		item_type = type;
		item_id = id;
		lang = lan;
	}
	public boolean equals(Object o){
		return item_type == ((Log)o).item_type && item_id == ((Log)o).item_id;
	}
}

public class EntityBrowsing {
	/**
	 * 关键词搜索对应实体
	 * @param kw
	 * @param lang
	 * @param userName. 当userName为null表示不考虑bookmarkname，否则考虑bookmark name.
	 * @return
	 */
	public static ArrayList<QuadItem> kw2Entity(String kw, String lang,String userName){
		ArrayList<QuadItem> items = new ArrayList<QuadItem>();
    	try {
    		Connection conn = DBConnectionFactory.getConnection();
    	    PreparedStatement ps = conn.
    	        prepareStatement("select entity_id, `type`,name,lang from identity_label,identity where identity.id=identity_label.entity_id and name COLLATE utf8_general_ci like ? ") ;
    	    String like ="%"+kw+"%" ;
    	    ps.setString(1, like) ;
    	    ResultSet rs = ps.executeQuery() ;
    		while ( rs.next() ) {
    			int memberId = rs.getInt("entity_id");
    			int memberType = rs.getInt("type");
    			String name = null;
    			String language = rs.getString("lang");
    			ArrayList<Entry<Integer, String>> types = null;
    			name = Entity.getNameByEntityID(memberId,lang);
    			types = Entity.getClassTypesById(memberId,language);
    			items.add(new QuadItem(memberType, memberId, name, types,language));
    		}
    	    rs.close();
    		ps.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return items;
	}
	
	/**
	 * @param start 起 始位置
	 * @param length 长度
	 * @param items 装载结果的数组即Collection排序列表中从start开始的总共length个元素
	 * @return 是否仍然存在元素
	 */
    public static boolean fetchCollections(int start,int length,String lang, ArrayList<QuadItem> items){
    	boolean flag = true;
    	try {
    		Connection conn = DBConnectionFactory.getConnection();
    		Statement stmt = conn.createStatement();
    		ResultSet rs = stmt.executeQuery(String.format(
    				"select user_day_visit.member_id " +
    				"from user_day_visit,visit_lang " +
    				"where user_day_visit.member_type= visit_lang.member_type and user_day_visit.member_id = visit_lang.member_id and visit_lang.lang='%s' and user_day_visit.member_type = %d " +
    				"group by member_id " +
    				"order by sum(times_recent) desc " +
    				"limit %d, %d",lang, 
    				Entity.COLLECTION, start, length));
    		
    		while ( rs.next() ) {
    			int memberId = rs.getInt("user_day_visit.member_id");
    			String name = Entity.getNameByEntityID(memberId,lang) ;
    			ArrayList<Entry<Integer, String>> types = Entity.getClassTypesById(memberId,lang);
    			items.add(new QuadItem(Entity.COLLECTION, memberId, name, types,lang));
    		}
    		rs.close();
    		
    		rs = stmt.executeQuery(String.format(
    				"select user_day_visit.member_id " +
    				"from user_day_visit,visit_lang " +
    				"where user_day_visit.member_type= visit_lang.member_type and user_day_visit.member_id = visit_lang.member_id and visit_lang.lang='%s' and user_day_visit.member_type = %d " +
    				"group by member_id " +
    				"order by sum(times_recent) desc " +
    				"limit %d, %d",lang, 
    				Entity.COLLECTION, start+length, 1));
    		if(!rs.next())
    			flag = false;
    		rs.close();
    		
    		stmt.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return flag;
    }

	/**
	 * get uri entities or custom entities
	 * @param start 起 始位置
	 * @param length 长度
	 * @param items 装载结果即实体排序列表（包含用户bookmark的和原始的）中从start开始的总共length个元素
	 * @return 是否还有元素
	 */
    public static boolean fetchEntities(int start,int length,String lang,ArrayList<QuadItem> items){
    	boolean flag = true;
    	try {
    		Connection conn = DBConnectionFactory.getConnection();
    		Statement stmt = conn.createStatement();
    		ResultSet rs = stmt.executeQuery(String.format(
    				"select user_day_visit.member_id, user_day_visit.member_type " +
    				"from user_day_visit,visit_lang " +
    				"where (user_day_visit.member_type = %d or user_day_visit.member_type = %d) and user_day_visit.member_type= visit_lang.member_type and user_day_visit.member_id=visit_lang.member_id " +
    				"and visit_lang.lang='%s' group by member_type,member_id " +
    				"order by sum(times_recent) desc " +
    				"limit %d, %d", 
    				Entity.CUSTOM_ENTITY, Entity.URI_ENTITY,lang, start, length));
    		
    		while ( rs.next() ) {
    			int memberId = rs.getInt("user_day_visit.member_id");
    			int memberType = rs.getInt("member_type");
    			String name = null;
    			ArrayList<Entry<Integer, String>> types = null;
    			if ( memberType == Entity.CUSTOM_ENTITY ) {
    				name = Entity.getNameByEntityID(memberId,lang);
    				types = Entity.getClassTypesById(memberId,lang);
    			} else if ( memberType == Entity.URI_ENTITY ) {
    				try {
						name = URILabelCache.getInstance().getLabel(memberId, lang) ;
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    				types = URIResource.getTypesById(memberId,lang);
    			}
    			items.add(new QuadItem(memberType, memberId, name, types,lang));
    		}
    		rs.close();
    		
    		rs =  stmt.executeQuery(String.format(
    				"select user_day_visit.member_id, user_day_visit.member_type " +
    				"from user_day_visit,visit_lang " +
    				"where (user_day_visit.member_type = %d or user_day_visit.member_type = %d) and user_day_visit.member_type= visit_lang.member_type and user_day_visit.member_id=visit_lang.member_id " +
    				"and visit_lang.lang='%s' group by member_type,member_id " +
    				"order by sum(times_recent) desc " +
    				"limit %d, %d", 
    				Entity.CUSTOM_ENTITY, Entity.URI_ENTITY,lang, start+length, 1));
    		if(!rs.next())
    			flag  = false;
    		rs.close();
    		
    		stmt.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return flag;
    }

    /**
     * 
     * @param groupID
     * @param start
     * @param length
     * @param items
     * @return
     */
	public static boolean fetchGroupEntities(int groupID, int start, int length, String lang,ArrayList<QuadItem> items){
//		ArrayList<QuadItem> items = new ArrayList<EntityBrowsing.QuadItem>();
		boolean flag = false;
		try {
			Connection conn = DBConnectionFactory.getConnection();
			StringBuffer sql = new StringBuffer("select id,`type` from identity where group_id=? order by update_time desc ");
			if(length>=0){
				sql.append(String.format(" limit %d,%d", start, length));
			}
			PreparedStatement pstmt = conn.prepareStatement(sql.toString());
			pstmt.setInt(1, groupID);
			ResultSet rs = pstmt.executeQuery();
			while(rs.next()){
				int memberId = rs.getInt("id");
				int memberType = rs.getInt("type");
				String name = null;
    			ArrayList<Entry<Integer, String>> types = null;
    			if ( memberType !=  Entity.URI_ENTITY ) {
    				name = Entity.getNameByEntityID(memberId,lang);
    				types = Entity.getClassTypesById(memberId,lang);
    			} else {
    				try {
						name = URILabelCache.getInstance().getLabel(memberId, lang) ;
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    				types = URIResource.getTypesById(memberId,lang);
    			}
				items.add(new QuadItem(memberType, memberId, name, types, lang));
			}
			rs.close();
			pstmt.close();
			conn.close();
			flag = true;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return flag;
	}
	/**
	 * @param start 起 始位置
	 * @param length 长度
	 * @param items.装载结果即 排序列表（包括bookmark的entity，原始的entity和集合）中从start开始的总共length个元素
	 * @return 是否还有其他元素
	 */
    public static boolean  fetchAll(int start,int length,String lang,ArrayList<QuadItem> items){
    	boolean flag =true;
    	try {
    		Connection conn = DBConnectionFactory.getConnection();
    		Statement stmt = conn.createStatement();
    		String str = String.format(
    				"select user_day_visit.member_id, user_day_visit.member_type " +
    				"from user_day_visit,visit_lang " +
    				"where  (user_day_visit.member_type = %d or user_day_visit.member_type = %d or user_day_visit.member_type = %d) and user_day_visit.member_type= visit_lang.member_type and user_day_visit.member_id =visit_lang.member_id" +
    				" and visit_lang.lang='%s' group by member_type,member_id " +
    				"order by sum(times_recent) desc " +
    				"limit %d, %d", 
    				Entity.COLLECTION,Entity.CUSTOM_ENTITY,Entity.URI_ENTITY,lang,start, length);
    		ResultSet rs = stmt.executeQuery(str);
    		while ( rs.next() ) {
    			int memberId = rs.getInt("member_id");
    			int memberType = rs.getInt("member_type");
    			String name = null;
    			ArrayList<Entry<Integer, String>> types = null;
    			if ( memberType == Entity.COLLECTION || memberType == Entity.CUSTOM_ENTITY) {
    				name = Entity.getNameByEntityID(memberId,lang);
    				types = Entity.getClassTypesById(memberId,lang);
    			} else if ( memberType == Entity.URI_ENTITY ) {
    				try {
						name = URILabelCache.getInstance().getLabel(memberId, lang) ;
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    				types = URIResource.getTypesById(memberId,lang);
    			}
    			items.add(new QuadItem(memberType, memberId, name, types,lang));
    		}
    		rs.close();
    		
    		str = String.format(
    				"select user_day_visit.member_id, user_day_visit.member_type " +
    				"from user_day_visit,visit_lang " +
    				"where (user_day_visit.member_type = %d or user_day_visit.member_type = %d or user_day_visit.member_type = %d) and user_day_visit.member_type= visit_lang.member_type and user_day_visit.member_id =visit_lang.member_id" +
    				" and visit_lang.lang='%s' group by member_type,member_id " +
    				"order by sum(times_recent) desc " +
    				"limit %d, %d", 
    				Entity.COLLECTION,Entity.CUSTOM_ENTITY,Entity.URI_ENTITY,lang,start+length, 1);
    		rs = stmt.executeQuery(str);
    		if(!rs.next())
    			flag = false;
    		rs.close();
    		stmt.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return flag;
    }
    
    /**
     * get the entities or collection bookmarked by the user
     * @param user
     * @param start
     * @param items
     * @return
     */
    public static boolean fetchUserAll(String user,int start,int length,String lang,ArrayList<QuadItem> items ){
    	boolean flag = true;
    	int userId = User.getUserIdByName(user);
    	if ( userId < 0 ) return false;
    	try {
    		Connection conn = DBConnectionFactory.getConnection();
    		Statement stmt = conn.createStatement();
    		String sql = String.format(
    				"select entity_type, entity_id,name" +
    				" from bm_entity, bookmark " +
    				"where (entity_type = %d or entity_type = %d or entity_type = %d) and bm_entity.bm_id = bookmark.id" +
    				"  and bookmark.user_id = %d and bookmark.lang='%s'" +
    				" order by name " +
    				"limit %d, %d",
    				Entity.COLLECTION,Entity.CUSTOM_ENTITY,Entity.URI_ENTITY,userId, lang,start, length);
    		ResultSet rs = stmt.executeQuery(sql);
    		while ( rs.next() ) {
    			int eid = rs.getInt("entity_id");
    			int etype = rs.getInt("entity_type");
    			String name = rs.getString("name");
    			ArrayList<Entry<Integer, String>> types = null;
    			if ( etype == Entity.COLLECTION || etype == Entity.CUSTOM_ENTITY) {
    				types = Entity.getClassTypesById(eid,lang);
    				
    			} else if ( etype == Entity.URI_ENTITY ) {
    				types = URIResource.getTypesById(eid,lang);
    			}
    			items.add(new QuadItem(etype, eid, name, types,lang));
    		}
    		rs.close();
    		
    		 rs = stmt.executeQuery(String.format(
    				"select entity_type, entity_id,name" +
     				" from bm_entity, bookmark " +
     				"where (entity_type = %d or entity_type = %d or entity_type = %d) and bm_entity.bm_id = bookmark.id" +
     				"  and bookmark.user_id = %d and bookmark.lang='%s'" +
     				" order by name " +
     				"limit %d, %d",
     				Entity.COLLECTION,Entity.CUSTOM_ENTITY,Entity.URI_ENTITY,userId, lang,start+length, 1));
    		 if(!rs.next())
    			 flag = false;
    		 rs.close();
    		
    		stmt.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return flag;
    }
    
    /**
     * get the collection bookmarked by the user
     * @param user
     * @param start
     * @param length
     * @param items
     * @return
     */
    public static boolean fetchUserCollection(String user,int start,int length,String lang,ArrayList<QuadItem> items){
    	boolean flag = true;
    	try {
    		int userID = User.getUserIdByName(user) ;
    		Connection conn = DBConnectionFactory.getConnection();
    		Statement stmt = conn.createStatement();
    		ResultSet rs = stmt.executeQuery(String.format(
    				"select entity_id,name" +
    				" from bm_entity, bookmark " +
    				"where bm_entity.bm_id = bookmark.id" +
    				"	and entity_type=%d and bookmark.user_id = %d and bookmark.lang='%s' " +
    				" order by name " +
    				"limit %d, %d",
    				Entity.COLLECTION,userID, lang,start, length));
    		
    		while ( rs.next() ) {
    			int memberId = rs.getInt("entity_id");
    			String name = rs.getString("name");
    			ArrayList<Entry<Integer, String>> types = null;
    			name = Entity.getNameByEntityID(memberId,lang) ;
    			types = Entity.getClassTypesById(memberId,lang);
    			items.add(new QuadItem(Entity.COLLECTION, memberId, name, types,lang));
    		}
    		rs.close();
    		
    		rs = stmt.executeQuery(String.format(
      				"select entity_id,name" +
    				" from bm_entity, bookmark " +
    				"where bm_entity.bm_id = bookmark.id" +
    				"	and entity_type=%d and bookmark.user_id = %d and bookmark.lang='%s' " +
    				" order by name " +
    				"limit %d, %d",
    				Entity.COLLECTION,userID, lang,start+length, 1));
    		if(!rs.next())
    			flag = false;
    		rs.close();
    		
    		stmt.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return flag;
    }
    
    /**
     * get the entities bookmarked by the user
     * @param user
     * @param start
     * @param length
     * @param items
     * @return
     */
    public static boolean  fetchUserEntities(String user,int start,int length,String lang,ArrayList<QuadItem> items){
    	boolean flag = true;
    	try {
    		int userID = User.getUserIdByName(user) ;
    		Connection conn = DBConnectionFactory.getConnection();
    		Statement stmt = conn.createStatement();
    		ResultSet rs = stmt.executeQuery(String.format(
    				"select entity_type,entity_id,name" +
    				" from bm_entity, bookmark " +
    				"where bm_entity.bm_id = bookmark.id" +
    				"	and (entity_type=%d or entity_type=%d) and bookmark.user_id = %d and bookmark.lang='%s' " +
    				" order by name " +
    				"limit %d, %d",
    				Entity.CUSTOM_ENTITY,Entity.URI_ENTITY, userID, lang,start, length));
    		
    		while ( rs.next() ) {
    			int eid = rs.getInt("entity_id");
    			int etype = rs.getInt("entity_type");
    			String name = rs.getString("name");
    			ArrayList<Entry<Integer, String>> types = null;
    			if ( etype == Entity.COLLECTION || etype == Entity.CUSTOM_ENTITY) {
    				types = Entity.getClassTypesById(eid,lang);
    				
    			} else if ( etype == Entity.URI_ENTITY ) {
    				types = URIResource.getTypesById(eid,lang);
    			}
    			items.add(new QuadItem(etype, eid, name, types,lang));
    		}
    		rs.close();
    		
    		rs = stmt.executeQuery(String.format(
    				"select entity_type,entity_id,name" +
    				" from bm_entity, bookmark " +
    				"where bm_entity.bm_id = bookmark.id" +
    				"	and (entity_type=%d or entity_type=%d) and bookmark.user_id = %d and bookmark.lang='%s' " +
    				" order by name " +
    				"limit %d, %d",
    				Entity.CUSTOM_ENTITY,Entity.URI_ENTITY,userID, lang,start+length, 1));
    		if(!rs.next())
    			flag = false;
    		rs.close();
    		
    		stmt.close();
    		conn.close();
    	} catch (SQLException e) {
    		e.printStackTrace();
		}
    	return flag;
    }
    /**
     * get the origin uri coreferenced ones
     * @param uriID
     * @return must contain self
     */
    public static HashSet<Integer> getSameAsURIs(int uriID){
    	HashSet<Integer> result =new HashSet<Integer>();
    	try {
			result = SameAsCache.getInstance().getSameAsURIs(uriID) ;
			result.add(uriID) ;
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	return result;
    }
    
    /**
     * get user defined sameas origin uris of the custom 
     * just the identity first layer origin uris
     * @param customEntityID
     * @return empty if one
     */
    public static HashSet<Integer> getUserDefinedSameAsURIs(int customEntityID){
    	HashSet<Integer> result =new HashSet<Integer>();
		PreparedStatement stmt;
		try {
			Connection conn = DBConnectionFactory.getConnection();
			stmt = conn.prepareStatement(
					"select uri_id from identity_entity where identity_id=?");
			stmt.setInt(1, customEntityID) ;
			ResultSet rs = stmt.executeQuery();
			while(rs.next()){
				result.add(rs.getInt("uri_id")) ;
			}
			rs.close();
			stmt.close();
			conn.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
    }
    
    /**
     * get the entity's relevant origin uris but not containing sameas，因为sameas都推荐给自定义实体中
     * @param type. Custom entity or origin uri
     * @param id. The id
     * @return
     */
    public static HashSet<Integer> getEntityRelevantURIs(int type, int id){
    	HashSet<Integer> result = new HashSet<Integer>();
    	if(type==Entity.URI_ENTITY){
    		result.add(id);
    	}else{
    		HashSet<Integer> members = Entity.getMembersByEntityId(id);
    		for(Integer uid :members){
    			result.add(uid);
    		}
    	}
    	return result;
    }
    
    /**
     * get the entity's relevant origin uris without sameas
     * @param type. Custom entity or origin uri
     * @param id. The id
     * @return
     */
    public static HashSet<Integer> getEntityMembersWithoutSameas(int type, int id){
    	HashSet<Integer> result = new HashSet<Integer>();
    	if(type!=Entity.URI_ENTITY){
    		HashSet<Integer> part1 = Entity.getMembersByEntityId(id);
    		/*get part1 sameas*/
    		for(Integer uid :part1){
    			result.add(uid);
    		}
    	}else{
    		result.add(id);
    	}
    	return result;
    }
    
    /**
     * 返回最近浏览的历史记录（最近访问的实体列表）
     * @return
     */
    public static ArrayList<QuadItem> getLatestEntityInHistory(int userId, int requiredNum){
    	ArrayList<QuadItem> latestEntities = new ArrayList<QuadItem>();
    	try{	
    		Connection conn = DBConnectionFactory.getConnection();
    		
    		ArrayList<Log> logs = new ArrayList<Log>();
    		PreparedStatement ps = conn.
    	    	prepareStatement("SELECT item_type, item_id, lang from visit_logs where user_id = ? AND item_type in (1, 2) AND event_type = 'visit' AND view_id =-1 ORDER BY visit_time DESC");
    		ps.setInt(1, userId);
    		ResultSet rs = ps.executeQuery();
    		try{
    				int count = 0;
    				while(rs.next()){
    					int itemType = rs.getInt("item_type");
    					int itemId = rs.getInt("item_id");
    					String lang = rs.getString("lang");
    					Log l = new Log(itemId, itemType, lang);
    					//latestEntities.add(PackingService.pack
    					//		(itemId, itemType, lang));
    					
    					boolean contains = false;
    					for(Log ll : logs){
    						if(ll.item_id == itemId && ll.item_type == itemType){
    							contains = true;
    							break;
    						}
    					}
    					if(contains){
    						continue;
    					}
    					else{
    						logs.add(l);
    						count++;
    						if(count == requiredNum)
    							break;
    					}
    				}
    		}finally{
    				conn.close();
    				ps.close();
    				rs.close();
    		}
    		for(Log l : logs){
    			latestEntities.add(PackingService.pack(l.item_id, l.item_type, l.lang));
    		}
    	}catch(SQLException e){
    		e.printStackTrace();
    	}
    	return latestEntities; 	
    }
    public static ArrayList<QuadItem> getLatestCollectionInHistory(int userId, int requiredNum){
    	ArrayList<QuadItem> latestEntities = new ArrayList<QuadItem>();
    	try{
    		ArrayList<Log> logs = new ArrayList<Log>();
    		Connection conn = DBConnectionFactory.getConnection();
    		PreparedStatement ps = conn.
    	    	prepareStatement("SELECT item_type, item_id, lang from visit_logs where user_id = ? AND item_type = 3 AND event_type = 'visit' AND view_id =-1 ORDER BY visit_time DESC");
    		ps.setInt(1, userId);
    		ResultSet rs = ps.executeQuery();
    		try{
    				int count = 0;
    				while(rs.next()){
    					int itemType = rs.getInt("item_type");
    					int itemId = rs.getInt("item_id");
    					String lang = rs.getString("lang");
    					Log l = new Log(itemId, itemType, lang);
    					//latestEntities.add(PackingService.pack
    					//		(itemId, itemType, lang));
    					if(logs.contains(l))
    						continue;
    					else{
    						logs.add(l);
    						count++;
    						if(count == requiredNum)
    							break;
    					}
    				}
    		}finally{
    				conn.close();
    				ps.close();
    				rs.close();
    		}
    		for(Log l : logs){
    			latestEntities.add(PackingService.pack(l.item_id, l.item_type, l.lang));
    		}
    	}catch(SQLException e){
    		e.printStackTrace();
    	}
    	return latestEntities; 	
    }
    

    
    /**
     * 根据当前浏览的实体，推荐相关的实体列表
     * @param genre.标示浏览实体是自定义实体( Entity.CUSTOM_ENTITY,Entity.COLLECTION)还是uri named实体(Entity.URI_ENTITY)
     * @param id.浏览实体的id
     * @param lang. 语言
     * @return
     */
    public static ArrayList<LinkedList<QuadItem>> getRecommendEntity(int genre,int id, String lang, int length){
    	ArrayList<RecommandSrc> recSrcs = new ArrayList<RecommandSrc>();
    	recSrcs.add(new GenHistRecomm(lang));
    	if(genre == 1){
    		recSrcs.add(new CustEntityRelateRecomm(lang));
    	}else if(genre == 3){
    		recSrcs.add(new CollectionRelateRecomm(lang));
    	}else{
    		recSrcs.add(new uriRelationRecomm(lang));
    	}
    	
    	ArrayList<LinkedList<QuadItem>> ret = new ArrayList<LinkedList<QuadItem>>(recSrcs.size());
    	
    	Iterator<RecommandSrc> iter = recSrcs.iterator();
    	while(iter.hasNext()){
    		try {
				ret.add(iter.next().getRecommandItems(id, genre, length));
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    	
    	//去掉GenHistRecomm中跟RelateRecomm重复的实体
    	LinkedList<QuadItem> fir = ret.get(0), sec = ret.get(1);
    	
    	Iterator<QuadItem> iter1 = fir.iterator();
    	while(iter1.hasNext()){
    		QuadItem it = iter1.next();
    		if(sec.contains(it))
    			iter1.remove();
    	}
    	
    	if(length < fir.size()){
    		int i = 0;
    		iter1 = fir.iterator();
    		while(iter1.hasNext()){
    			if(i < length){
    				iter1.next();
    				i++;
    				continue;
    			}
    			iter1.next();
    			iter1.remove();
    			i++;
    		}
    	}
    	return ret;
    }
   
    
    @Deprecated
	public static void addVisitEntityEvent(int userId, int itemType, int itemId,  Date visitTime, String lang){
		
			SimpleDateFormat m=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String vTime = m.format(visitTime);
			try{
				Connection conn = DBConnectionFactory.getConnection();
				Statement state = conn.createStatement();
				String sql = "INSERT INTO sview.visit_logs" +
						"(user_id, event_type, item_type, item_id, view_id, visit_time, lang) VALUES("
						+ userId + ", 'visit', "+ itemType + ", "+ itemId + ", NULL, '" + vTime + "', '" + lang + "'); ";
				state.executeUpdate(sql);
				conn.close();
				state.close();
			}catch(SQLException e){
				e.printStackTrace();
			}
	}
	@Deprecated
	public static void addVisitViewEvent(int userId, int viewId,  Date visitTime, String lang){
		
		SimpleDateFormat m=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String vTime = m.format(visitTime);
		try{
			Connection conn = DBConnectionFactory.getConnection();
			Statement state = conn.createStatement();
			String sql = "INSERT INTO sview.visit_logs" +
					"(user_id, event_type, item_type, item_id, view_id, visit_time, lang) VALUES("
					+ userId + ", 'visit', NULL, NULL," + viewId + ", '" + vTime + "', '" + lang + "'); ";
			state.executeUpdate(sql);
			conn.close();
			state.close();
		}catch(SQLException e){
			e.printStackTrace();
		}
}
	
	
	/**
	 * 
	 * @param userId
	 * @param visitTime
	 * @param isLogIn 为true时为login，为false时为logout
	 */
	@Deprecated
	public static void addLoginInOutEvent(int userId, Date visitTime, boolean isLogIn, String lan){
		SimpleDateFormat m=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String vTime = m.format(visitTime);
		String event;
		if(isLogIn){
			event = "login";
		}
		else{
			event = "logout";
		}
		try{
		Connection conn = DBConnectionFactory.getConnection();
		PreparedStatement state = conn.prepareStatement("INSERT INTO visit_logs (user_id, event_type, visit_time, lang, item_id, item_type, view_id) VALUES(" +
        		"?, ?, ?, ?, NULL, NULL, NULL) ");
		state.setInt(1, userId);
		state.setString(2, event);
		state.setString(3, vTime);
		state.setString(4, lan);
		state.executeUpdate();
		conn.close();
		state.close();
	}catch(SQLException e){
		e.printStackTrace();
	}
	}
    /**
     * 由于DBpedia等网站会被封掉，因此使用falcons数据集作为后备
     * @param uri
     * @return 是否得到相应的falcons数据集
     */
    public static boolean getReserveRDFDescription(String uri){
    	 String uri_str= Fetch.removeFragment(uri);
 		 if(!Fetch.isAcceptableURI(uri_str))
 			 return false;
 		 
 		 boolean result = false;
 		 try {
 	 		 Connection falconConnection = DBConnectionFactory.getFalconConnection();
 	 		 Connection connection = DBConnectionFactory.getConnection();
			PreparedStatement stmt = falconConnection.prepareStatement("select dereference_doc_uri_id from " +
			 		"uri where uri=? ");
			PreparedStatement derefStmt= connection.prepareStatement("update uri " +
					"set deref=?,lastping=?,expire=? where id =? "); 
			stmt.setString(1, uri_str);
			ResultSet rs =stmt.executeQuery();
			if(rs.next()){
				int deref_doc = rs.getInt("dereference_doc_uri_id");
				if(deref_doc>0){
					result = true;
					//triple
					insertFalconTripleOfDoc(deref_doc);
					//uri
					try {
						String deref_uri= FalconURIIDCache.getInstance().getURI(deref_doc);
						int sviewDerefID = URIIDCache.getInstance().getURIID(deref_uri, true) ;
						int entityID  =  URIIDCache.getInstance().getURIID(uri_str, true) ;
						long timestamp = System.currentTimeMillis();
						long expireTime = timestamp + Crawler.RDF_DOC_EXPIRE_TIME;
						derefStmt.setInt(1, sviewDerefID) ;
						derefStmt.setLong(2, timestamp) ;
						derefStmt.setLong(3, expireTime);
						derefStmt.setInt(4, entityID) ;
						derefStmt.executeUpdate();
						
						if(entityID!=sviewDerefID){
							derefStmt.setInt(1, sviewDerefID) ;
							derefStmt.setLong(2, timestamp) ;
							derefStmt.setLong(3, expireTime);
							derefStmt.setInt(4, sviewDerefID) ;
							derefStmt.executeUpdate();
						}
						
					} catch (Throwable e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				}
			}
			rs.close();
			stmt.close();
			derefStmt.close();
			falconConnection.close();
			connection.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
 		 
 		 
 		 return result;
    }
    
    /**
     * 将falcon下特定文档中的三元组拿过来用
     * @param falconDocID
     */
    private static void insertFalconTripleOfDoc(int falconDocID){
    	try {
        	Connection falconConnection = DBConnectionFactory.getFalconConnection();
     		Connection connection = DBConnectionFactory.getConnection();
    		Statement delstmtStatement = connection.createStatement();
	    	String falconDOCURI;
			try {
				falconDOCURI = FalconURIIDCache.getInstance().getURI(falconDocID);
				int mydocid= URIIDCache.getInstance().getURIID(falconDOCURI, true);
				delstmtStatement.executeUpdate("delete from quadruple where doc_id="+mydocid);
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			PreparedStatement stmt = falconConnection.prepareStatement("select s,p,o,c,lang,datatype_uri_id,sentence_hash from" +
			" quadruple where c=? ");
			
			PreparedStatement derefStmt= connection.prepareStatement("insert into quadruple(s,p,o,doc_id,lang,datatypeid,sentence_hash) value(?,?,?,?,?,?,?)"); 
		    stmt.setInt(1, falconDocID);
		    ResultSet rs = stmt.executeQuery();
		    while(rs.next()){
		    	String sstr =  getSViewStr(rs.getString("s"));
		    	String pstr=getSViewStr(rs.getString("p"));
		    	String ostr = getSViewStr(rs.getString("o"));
		    	int doc_id = -1;
		    	String lang = rs.getString("lang");
		    	int datatypeid = 0;
		    	byte[] hash  = rs.getBytes("sentence_hash");
		    	
		    	int falconCID = rs.getInt("c");
		    	String falconCURI;
				try {
					falconCURI = FalconURIIDCache.getInstance().getURI(falconCID);
					doc_id= URIIDCache.getInstance().getURIID(falconCURI, true);
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
				int falcondatatypeid = rs.getInt("datatype_uri_id");
				String falconDTypeURI;
				try {
					falconDTypeURI = FalconURIIDCache.getInstance().getURI(falcondatatypeid);
					if(falconDTypeURI!=null)
						datatypeid= URIIDCache.getInstance().getURIID(falconDTypeURI, true);
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				derefStmt.setString(1, sstr);
				derefStmt.setString(2, pstr);
				derefStmt.setString(3, ostr);
				derefStmt.setInt(4, doc_id);
				derefStmt.setString(5, lang);
				if(datatypeid>0){
					derefStmt.setInt(6, datatypeid) ;
				}else{
					derefStmt.setNull(6,java.sql.Types.INTEGER);
				}
				derefStmt.setBytes(7, hash);
				derefStmt.executeUpdate();
		    }
		    rs.close();
			stmt.close();
			derefStmt.close();
			delstmtStatement.close();
		    falconConnection.close();
		    connection.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    
    /**
     * 根据falcon四元组表中的内容生成SView表中的内容
     * @param falconStr
     * @return
     */
    private static String getSViewStr(String falconStr){
    	String result =null;
    	if(falconStr.startsWith("u")){
    		int falconID = Integer.valueOf(falconStr.substring(1));
    		try {
				String falconURI = FalconURIIDCache.getInstance().getURI(falconID);
				int myID = URIIDCache.getInstance().getURIID(falconURI, true);
				result = "u"+myID;
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		
    	}else if(falconStr.startsWith("b")){
    		String str = falconStr.substring(1);
    		String[] array = str.split(":");
    		int falconID = Integer.valueOf(array[0]);
    		int nodeID =  Integer.valueOf(array[1]);
    		try {
				String falconURI = FalconURIIDCache.getInstance().getURI(falconID);
				int myID = URIIDCache.getInstance().getURIID(falconURI, true);
				result = "b"+myID+":"+nodeID;
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		
    	}else if(falconStr.startsWith("l")){
    		result = falconStr;
    	}
    	return result;
    }
    
    
    /**
     * 判断一个原始的URI能否得到RDF描述
     * @param uri. uri string
     * @return 
     */
    public static boolean hasRDFDescription(String uri_str){
    	 boolean result = true;
   	 	 String uri= Fetch.removeFragment(uri_str);
		 if(!Fetch.isAcceptableURI(uri))
			 return false;
		 int entityID = 0;
		try {
			entityID = URIIDCache.getInstance().getURIID(uri_str, true);
		} catch (Throwable e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		 URIResource resource = ResourceFactory.getInstance().createURIResource(uri_str);
		 if(entityID>0){
			 //查看是否已经获得相应的RDF数据
			 String status = DBOperations.getValidStatus(entityID);
			 if(!status.equals(URIResource.VALID)&&
						Crawler.getInstance().checkStatus(resource)==Crawler.STATUS_UNSUBMITTED){
				 Crawler.getInstance().submitURI(resource) ; 
				 Crawler.getInstance().promoteWeight(resource, Element.LEVEL_2);
				 boolean wait = true;
				 while(wait){
					 wait = false;
				     if(Crawler.getInstance().checkStatus(resource)!=Crawler.STATUS_DONE)
				    	 wait = true;
				     try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				 }
			 }
			 status = DBOperations.getSuccessStatus(entityID);
			 
			 if(!status.equals(URIResource.VALID_SUCCEED))
				 result = false;
		 }
			
       return result;
    }
    
    
    static public class QuadItem{
    	//分为
//    	Bookmark.CUSTOM_ENTITY = 1;
//    	Bookmark.URI_ENTITY = 2;
//    	Bookmark.COLLECTION = 3;
    	//实体类型
    	private int genre;
    	//实体id
    	private int id;
    	//实体名字
    	private String name = null;
    	//实体的语言
    	private String language = null;
    	//实体的类型
    	private ArrayList<Entry<Integer, String>> types = new ArrayList<Entry<Integer,String>>();
    	
    	public QuadItem(int genre,int id,String name,ArrayList<Entry<Integer, String>> types,String lang){
    		this.genre = genre;
    		this.id = id;
    		this.name = name;
    		this.types.addAll(types);
    		this.language = lang;
    	}
		public int getGenre() {
			return genre;
		}
		public int getId() {
			return id;
		}
		public String getName() {
			return name;
		}
		public ArrayList<Entry<Integer, String>> getTypes() {
			return types;
		}
		public String getLang(){
			return this.language;
		}
		public boolean equals(Object o){
			return (this.genre == ((QuadItem)o).getGenre()) && (this.id == ((QuadItem)o).getId());
		}
    }
    public static void main(String[] args) throws SQLException{
    	
    	ArrayList<LinkedList<QuadItem>> res = EntityBrowsing.getRecommendEntity(3, 242, "en", 5);
    	LinkedList<QuadItem> l1 = res.get(0), l2 = res.get(1);
    	for(QuadItem qi : l1){
    		System.out.println("fir:" + qi.id + " " + qi.genre);
    	}
    	for(QuadItem qi : l2){
    		System.out.println("sec:" + qi.id + " " + qi.genre);
    	}
    	/*
    	ArrayList<QuadItem> res = EntityBrowsing.getLatestCollectionInHistory(7, 10);
    	for(QuadItem q : res)
    		System.out.println(q.id + " " + q.genre);*/
    }
}

